package com.ericsson.mq.service;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.json.JSONUtil;
import com.ericsson.enap.modules.autoCheck.entity.AutoCheck;
import com.ericsson.enap.modules.autoCheck.entity.AutoCheckItem;
import com.ericsson.enap.modules.autoCheck.service.IEopsTemplateExecuteService;
import com.ericsson.enap.modules.base.entity.EnipBaseNetelement;
import com.ericsson.enap.modules.base.mapper.EnipBaseNetelementMapper;
import com.ericsson.enap.modules.enm.entity.EnipEnmAlarmData;
import com.ericsson.enap.modules.enm.entity.EnipEnmAlarmLog;
import com.ericsson.enap.modules.enm.entity.EnipEnmEopsItem;
import com.ericsson.enap.modules.enm.entity.EnipEnmEopsLog;
import com.ericsson.enap.modules.enm.entity.EnipEnmKpiAlarmCondition;
import com.ericsson.enap.modules.enm.mapper.EnipEnmAlarmDataMapper;
import com.ericsson.enap.modules.enm.mapper.EnipEnmAlarmLogMapper;
import com.ericsson.enap.modules.enm.mapper.EnipEnmEopsItemMapper;
import com.ericsson.enap.modules.enm.mapper.EnipEnmEopsLogMapper;
import com.ericsson.enap.modules.enm.mapper.EnipEnmKpiAlarmConditionMapper;
import com.ericsson.mq.constants.RabbitMqConsts;
import com.ericsson.mq.domain.Alarm;
import com.ericsson.mq.domain.Attribute;
import com.ericsson.mq.domain.EnipClearAlarmObject;
import com.ericsson.mq.domain.EnipKpiResult;
import com.ericsson.mq.domain.EnmAlarmObject;
import com.ericsson.mq.domain.Severity;
import com.ericsson.mq.util.SendAlarmUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
@Slf4j(topic = "mqAlarmConsumer")
@Service
public class EnmAlarmService {

    public static final int BIZ_TYPE_KPI = 1;
    public static final int BIZ_TYPE_KPI_EOPS = 2;
    public static final int BIZ_TYPE_CHECK_KPI = 3;
    public static final int BIZ_TYPE_CHECK_KPI_EOPS = 4;
    public static final int BIZ_TYPE_CHECK = 5;
    private static final int ALARM_STATUS_CLEAR = 0;
    private static final int ALARM_STATUS_CREATE = 1;
    private static final int ALARM_STATUS_NOT_SEND = 2;
    private static final int BIZ_SUB_TYPE_KPI = 0;
    private static final int THRESHOLD_TYPE_NOT_EQUALS = 3;
    private static final int THRESHOLD_TYPE_WAVE = 4;
    private static final int INIT_MINUTE = 0;
    private static final int CONFIG_STATUS_ENABLED = 1;
    private static final int SEND_FLAG_NOT_SEND = 2;
    private static final int SEND_FLAG_PENDING = 0;
    private static final int SEND_FLAG_SUCCESS = 1;
    private static final int SEND_FLAG_FAILED = 0;
    private static final int ENM_POST_STATUS_SUCCESS = 200;
    private static final int ENM_SERVER_ALL = 3;
    private static final int ENM_SERVER_ENM01 = 1;
    private static final int ENM_SERVER_ENM02 = 2;
    private static final String CHECK_RESULT_NORMAL = "1";
    private static final String CHECK_RESULT_ABNORMAL = "0";
    private static final int CLEAR_TYPE_NORMAL = 2;


    @Autowired
    EnipEnmAlarmDataMapper enipEnmAlarmDataMapper;

    @Autowired
    EnipEnmAlarmLogMapper enipEnmAlarmLogMapper;

    @Autowired
    EnipEnmKpiAlarmConditionMapper enipEnmKpiAlarmConditionMapper;

    @Autowired
    EnipBaseNetelementMapper enipBaseNetelementMapper;

    @Autowired
    EnipEnmEopsLogMapper enipEnmEopsLogMapper;

    @Autowired
    EnipEnmEopsItemMapper enipEnmEopsItemMapper;

    @Autowired
    IEopsTemplateExecuteService eopsTemplateExecuteService;

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Value("${enm01LoginHost}")
    private String host1;

    @Value("${enm01LoginUsername}")
    private String username1;

    @Value("${enm01LoginPassword}")
    private String password1;

    @Value("${enm02LoginHost}")
    private String host2;

    @Value("${enm02LoginUsername}")
    private String username2;

    @Value("${enm02LoginPassword}")
    private String password2;


    /**
     * 消费指标数据（告警入口|取消告警入口）
     *
     * @param kpiResult 指标结果
     */
    public void doService(EnipKpiResult kpiResult) {

        EnipEnmKpiAlarmCondition alarmConfig = getAlarmConfig(kpiResult.getKpiId(), kpiResult.getBizType());
        if (alarmConfig == null) {
            log.error("alarmConfig is null, program exit");
            return;
        }
        if (alarmConfig.getEnmServer() == null) {
            log.error("config id is {},enmServer is null, program exit",alarmConfig.getId());
            return;
        }
        if (alarmConfig.getEnmServer() == ENM_SERVER_ALL) {
            doServiceToEnm(ENM_SERVER_ENM01, kpiResult.getBizType(), kpiResult, alarmConfig);
            doServiceToEnm(ENM_SERVER_ENM02, kpiResult.getBizType(), kpiResult, alarmConfig);
        } else {
            doServiceToEnm(alarmConfig.getEnmServer(), kpiResult.getBizType(), kpiResult, alarmConfig);
        }
    }

    /**
     * 消费指标数据（取消告警入口）
     *
     * @param enipClearAlarmObject 告警消除信息
     */
    public void doClearService(EnipClearAlarmObject enipClearAlarmObject) {

        clearAlarm(enipClearAlarmObject.getAlarmConfig(), enipClearAlarmObject.getKpiResult(), enipClearAlarmObject.getAlarmData(), INIT_MINUTE);

    }

    /**
     * 消费指标数据 告警|取消告警到指定enm
     *
     * @param enmServer   目标enm
     * @param bizType     业务类型
     * @param kpiResult   指标结果
     * @param alarmConfig 告警配置
     */
    private void doServiceToEnm(final Integer enmServer, Integer bizType, EnipKpiResult kpiResult, EnipEnmKpiAlarmCondition alarmConfig) {
        //查询告警数据表，是否有记录
        EnipEnmAlarmData alarmData = getStatusData(enmServer, bizType, kpiResult, SEND_FLAG_SUCCESS);
        if (alarmData == null) {
            //是否告警流程
            doAlarm(enmServer, alarmConfig, kpiResult, bizType);
        } else {
            //消除告警流程
            doClearAlarm(alarmConfig, kpiResult, alarmData);
        }
    }

    /**
     * 查询指定状态的告警数据
     *
     * @param enmServer 目标enm
     * @param bizType   业务类型
     * @param kpiResult 指标结果
     * @param sendFlag  发送标识
     * @return 返回告警数据
     */
    private EnipEnmAlarmData getStatusData(final Integer enmServer, Integer bizType, EnipKpiResult kpiResult, Integer sendFlag) {
        EnipEnmAlarmData queryParams = new EnipEnmAlarmData();
        queryParams.setNetId(kpiResult.getNetId());
        queryParams.setKpiId(kpiResult.getKpiId());
        queryParams.setBizType(bizType);
        queryParams.setSendFlag(sendFlag);
        queryParams.setEnmServer(enmServer);
        List<EnipEnmAlarmData> alarmDataList = enipEnmAlarmDataMapper.selectEnipEnmAlarmDataList(queryParams);
        if (alarmDataList != null && alarmDataList.size() > 0) {
            return alarmDataList.get(0);
        }
        return null;
    }

    /**
     * 告警流程入口
     *
     * @param enmServer   目标enm
     * @param alarmConfig 告警配置
     * @param kpiResult   指标结果
     * @param bizType     业务类型
     */
    private void doAlarm(final Integer enmServer, EnipEnmKpiAlarmCondition alarmConfig, EnipKpiResult kpiResult, Integer bizType) {
        LocalDateTime localDate = LocalDateTime.now();
        int hour = localDate.getHour();
        //在排除时段内，直接退出
        if (alarmConfig.getExclusionStartTime() != null && alarmConfig.getExclusionEndTime() != null &&
                alarmConfig.getExclusionStartTime() <= hour && hour <= alarmConfig.getExclusionEndTime()) {
            log.info("Exclusion time is {}-{}, current hour is {}, no alarm!",alarmConfig.getExclusionStartTime(),alarmConfig.getExclusionEndTime(),hour);
            return;
        }
        //巡检告警
        if (BIZ_TYPE_CHECK == alarmConfig.getDoWithType()) {

            if (CHECK_RESULT_ABNORMAL.equals(kpiResult.getValue())) {
                saveAndAlarm(enmServer, alarmConfig, kpiResult);
            }

        } else {
            if (alarmConfig.getThresholdType() == THRESHOLD_TYPE_NOT_EQUALS || alarmConfig.getThresholdType() == THRESHOLD_TYPE_WAVE) {
                doCycleAlarm(enmServer, alarmConfig, kpiResult, bizType);
            } else {
                doThresholdAlarm(enmServer, alarmConfig, kpiResult);
            }
        }
    }

    /**
     * @param enmServer   目标enm
     * @param alarmConfig 告警配置
     * @param kpiResult   告警结果
     */
    private void saveAndAlarm(Integer enmServer, EnipEnmKpiAlarmCondition alarmConfig, EnipKpiResult kpiResult) {

        //执行eops模板
        String eopsUuid = executeEopsTemplate(alarmConfig, kpiResult);

        EnmAlarmObject alarmObject = buildEnmAlarmObject(kpiResult.getNetId(), alarmConfig, Severity.resolve(alarmConfig.getSeverity()), alarmConfig.getThresholdValue(), kpiResult.getValue());
        EnipEnmAlarmData enmAlarmData = saveEnmAlarmData(enmServer, alarmConfig, kpiResult, SEND_FLAG_PENDING, alarmObject.getAlarmLog(), eopsUuid);

        //非系统内告警
        if (enmAlarmData.getEnmServer() != null && enmAlarmData.getEnmServer() > 0) {
            int statusCode = SendAlarmUtil.sendAlarm(enmAlarmData.getEnmServer() == 1 ? host1 : host2, enmAlarmData.getEnmServer() == 1 ? username1 : username2, enmAlarmData.getEnmServer() == 1 ? password1 : password2, alarmObject.getAlarmLog());
            alarmObject.setStatusCode(statusCode);
        }
        updateSendStatus(enmAlarmData, alarmObject.getStatusCode());

    }

    /**
     * 执行eops并入库
     * @param alarmConfig 告警配置
     * @param kpiResult 指标结果
     * @return 返回生成的eopsUuid
     */
    private String executeEopsTemplate(EnipEnmKpiAlarmCondition alarmConfig, EnipKpiResult kpiResult) {
        String eopsUuid = null;
        if (BIZ_TYPE_KPI_EOPS == alarmConfig.getDoWithType() || BIZ_TYPE_CHECK_KPI_EOPS == alarmConfig.getDoWithType()) {
            eopsUuid = UUID.fastUUID().toString(true);
            AutoCheck autoCheck = eopsTemplateExecuteService.execEopsTemplate(kpiResult.getNetId(), alarmConfig.getVisexcelId());
            if(autoCheck != null) {
                EnipEnmEopsLog enipEnmEopsLog = Convert.convert(EnipEnmEopsLog.class, autoCheck);
                enipEnmEopsLog.setEopsUuid(eopsUuid);
                enipEnmEopsLogMapper.insertEnipEnmEopsLog(enipEnmEopsLog);
                for (AutoCheckItem checkItem : autoCheck.getAutoCheckItemList()) {
                    EnipEnmEopsItem enipEnmEopsItem = Convert.convert(EnipEnmEopsItem.class, checkItem);
                    enipEnmEopsItem.setEnmEopsId(enipEnmEopsLog.getId());
                    enipEnmEopsItemMapper.insertEnipEnmEopsItem(enipEnmEopsItem);
                }
            }
        }
        return eopsUuid;
    }

    /**
     * 周期告警流程入口
     *
     * @param enmServer   目标enm
     * @param alarmConfig 告警配置
     * @param kpiResult   告警结果
     * @param bizType     业务类型
     */
    private void doCycleAlarm(final Integer enmServer, EnipEnmKpiAlarmCondition alarmConfig, EnipKpiResult kpiResult, Integer bizType) {
        //查询告警数据表，是否有记录
        EnipEnmAlarmData alarmData = getStatusData(enmServer, bizType, kpiResult, SEND_FLAG_NOT_SEND);
        if (alarmData == null) {
            //初始化周期告警记录
            EnipEnmAlarmData enmAlarmData = saveEnmAlarmData(enmServer, alarmConfig, kpiResult, SEND_FLAG_NOT_SEND, null, null);
            EnipEnmAlarmLog enmAlarmLog = new EnipEnmAlarmLog();
            BeanUtils.copyProperties(enmAlarmData, enmAlarmLog);
            enmAlarmLog.setId(null);
            enmAlarmLog.setAlarmStatus(ALARM_STATUS_NOT_SEND);
            enmAlarmLog.setSendFlag(SEND_FLAG_NOT_SEND);
            enipEnmAlarmLogMapper.insertEnipEnmAlarmLog(enmAlarmLog);
        } else if (alarmConfig.getThresholdType() == THRESHOLD_TYPE_NOT_EQUALS) {
            //是否周期告警
            if (!kpiResult.getValue().equals(alarmData.getLastKpiValue())) {
                //告警
                sendAlarmAndSaveLog(alarmData, kpiResult, alarmConfig);
            }
        } else {
            if(alarmConfig.getThresholdValue() == null){
                log.error("config id is {}, ThresholdValue is null, dynamic threshold alarm failed!",alarmConfig.getId());
                return;
            }
            if (isWaveExceeded(new BigDecimal(alarmConfig.getThresholdValue()), new BigDecimal(kpiResult.getValue()), new BigDecimal(alarmData.getLastKpiValue()))) {
                sendAlarmAndSaveLog(alarmData, kpiResult, alarmConfig);
            }
        }
    }

    /**
     * 判断是否超过告警门限
     *
     * @param threshold    门限值
     * @param currentValue 当前值
     * @param lastValue    上一次值
     * @return 返回判断结果
     */
    private static boolean isWaveExceeded(BigDecimal threshold, BigDecimal currentValue, BigDecimal lastValue) {
        BigDecimal ratio = threshold.divide(BigDecimal.valueOf(100));
        if (ratio.floatValue() > 1) {
            return currentValue.compareTo(lastValue.multiply(ratio)) > 0;
        } else {
            return currentValue.compareTo(lastValue.multiply(ratio)) < 0;
        }
    }


    /**
     * @param enmAlarmData 告警数据
     * @param kpiResult    指标结果
     * @param alarmConfig  告警配置
     */
    private void sendAlarmAndSaveLog(EnipEnmAlarmData enmAlarmData, EnipKpiResult kpiResult, EnipEnmKpiAlarmCondition alarmConfig) {

        //执行eops模板
        String eopsUuid = executeEopsTemplate(alarmConfig, kpiResult);
        //告警
        enmAlarmData.setEopsUuid(eopsUuid);
        enmAlarmData.setLastKpiValue(kpiResult.getValue());
        enmAlarmData.setCleanMinute(INIT_MINUTE);
        enmAlarmData.setSendFlag(SEND_FLAG_PENDING);

        EnmAlarmObject alarmObject = buildEnmAlarmObject(kpiResult.getNetId(), alarmConfig, Severity.resolve(alarmConfig.getSeverity()), enmAlarmData.getLastKpiValue(), kpiResult.getValue());
        enmAlarmData.setDetailLog(alarmObject.getAlarmLog());
        enipEnmAlarmDataMapper.updateEnipEnmAlarmData(enmAlarmData);

        //非系统内告警
        if (enmAlarmData.getEnmServer() != null && enmAlarmData.getEnmServer() > 0) {
            int statusCode = SendAlarmUtil.sendAlarm(enmAlarmData.getEnmServer() == 1 ? host1 : host2, enmAlarmData.getEnmServer() == 1 ? username1 : username2, enmAlarmData.getEnmServer() == 1 ? password1 : password2, alarmObject.getAlarmLog());
            alarmObject.setStatusCode(statusCode);
        }
        updateSendStatus(enmAlarmData, alarmObject.getStatusCode());
    }

    /**
     * 生成enmAlarmData对象并入库
     *
     * @param enmServer   目标enm
     * @param alarmConfig 告警配置
     * @param kpiResult   指标结果
     * @param sendFlag    发送标识
     * @return 返回告警数据对象
     */
    private EnipEnmAlarmData saveEnmAlarmData(Integer enmServer, EnipEnmKpiAlarmCondition alarmConfig, EnipKpiResult kpiResult, Integer sendFlag, String detailLog, String eopsUuid) {
        EnipEnmAlarmData enmAlarmData = new EnipEnmAlarmData();
        enmAlarmData.setBizType(alarmConfig.getDoWithType());
        enmAlarmData.setBizSubType(BIZ_SUB_TYPE_KPI);
        enmAlarmData.setNetId(kpiResult.getNetId());
        enmAlarmData.setKpiId(kpiResult.getKpiId());
        enmAlarmData.setKpiCreateTime(kpiResult.getKpiCreateTime());
        enmAlarmData.setCreateTime(DateUtil.now());
        enmAlarmData.setLastKpiValue(kpiResult.getValue());
        enmAlarmData.setCleanMinute(INIT_MINUTE);
        enmAlarmData.setSendFlag(sendFlag);
        enmAlarmData.setEnmServer(enmServer);
        enmAlarmData.setDetailLog(detailLog);
        enmAlarmData.setEopsUuid(eopsUuid);
        enmAlarmData.setAutocheckAlarmId(kpiResult.getAutoCheckItemId());
        enipEnmAlarmDataMapper.insertEnipEnmAlarmData(enmAlarmData);
        return enmAlarmData;
    }


    /**
     * 更新向enm告警的发送状态
     *
     * @param enmAlarmData 告警数据
     * @param sendStatus   告警发送状态
     */
    private void updateSendStatus(EnipEnmAlarmData enmAlarmData, int sendStatus) {
        EnipEnmAlarmLog enmAlarmLog = new EnipEnmAlarmLog();
        BeanUtils.copyProperties(enmAlarmData, enmAlarmLog);
        enmAlarmLog.setId(null);
        enmAlarmLog.setAlarmStatus(ALARM_STATUS_CREATE);

        if (ENM_POST_STATUS_SUCCESS == sendStatus) {
            enmAlarmData.setSendFlag(SEND_FLAG_SUCCESS);
            enipEnmAlarmDataMapper.updateEnipEnmAlarmData(enmAlarmData);

            enmAlarmLog.setSendFlag(SEND_FLAG_SUCCESS);
            enipEnmAlarmLogMapper.insertEnipEnmAlarmLog(enmAlarmLog);
        } else {
            enmAlarmLog.setSendFlag(SEND_FLAG_FAILED);
            enipEnmAlarmLogMapper.insertEnipEnmAlarmLog(enmAlarmLog);
        }
    }

    /**
     * 门限告警流程入口，是否进行门限告警
     *
     * @param enmServer   目标enm
     * @param alarmConfig 告警配置
     * @param kpiResult   指标结果
     */
    private void doThresholdAlarm(final Integer enmServer, EnipEnmKpiAlarmCondition alarmConfig, EnipKpiResult kpiResult) {
        if(alarmConfig.getThresholdValue() == null){
            log.error("config id is {}, ThresholdValue is null, doThresholdAlarm failed",alarmConfig.getId());
            return;
        }
        boolean isExceeded = isExceeded(alarmConfig.getThresholdType(), new BigDecimal(alarmConfig.getThresholdValue()), new BigDecimal(kpiResult.getValue()));
        //超过门限，告警
        if (isExceeded) {
            saveAndAlarm(enmServer, alarmConfig, kpiResult);
        }
    }

    /**
     * 消除告警流程入口
     *
     * @param alarmConfig  告警配置
     * @param kpiResult    指标结果
     * @param enmAlarmData 当前告警数据
     */
    private void doClearAlarm(EnipEnmKpiAlarmCondition alarmConfig, EnipKpiResult kpiResult, EnipEnmAlarmData enmAlarmData) {

        //巡检告警消除
        if (BIZ_TYPE_CHECK == alarmConfig.getDoWithType()) {
            if (CHECK_RESULT_NORMAL.equals(kpiResult.getValue())) {
                if (CLEAR_TYPE_NORMAL == alarmConfig.getClearType()) {
                    clearAlarm(alarmConfig, kpiResult, enmAlarmData, INIT_MINUTE);
                } else {
                    if (alarmConfig.getClearThresholdMinute() != null) {
                        //发送到延迟队列
                        EnipClearAlarmObject enipClearAlarmObject = new EnipClearAlarmObject();
                        enipClearAlarmObject.setAlarmData(enmAlarmData);
                        enipClearAlarmObject.setAlarmConfig(alarmConfig);
                        enipClearAlarmObject.setKpiResult(kpiResult);
                        rabbitTemplate.convertAndSend(RabbitMqConsts.EXCHANGE_DELAY_MODE, RabbitMqConsts.QUEUE_DELAY, enipClearAlarmObject, message -> {
                            message.getMessageProperties().setDelay(alarmConfig.getClearThresholdMinute() * 60000);
                            return message;
                        });
                        log.info("send message to delay queue,clearThresholdMinute is {} min,now time is {}",alarmConfig.getClearThresholdMinute(),DateUtil.now());
                    }else{
                        log.error("config id is{},clearThresholdMinute is null,send delay queue failed!",alarmConfig.getId());
                    }
                }
            }
        } else {
            //周期消除
            if (alarmConfig.getThresholdType() == THRESHOLD_TYPE_NOT_EQUALS) {
                boolean isValid = kpiResult.getValue().equals(enmAlarmData.getLastKpiValue());
                calcCycleOrClearAlarm(isValid, alarmConfig, kpiResult, enmAlarmData);
                //动态门限
            } else if (alarmConfig.getThresholdType() == THRESHOLD_TYPE_WAVE) {
                if(alarmConfig.getThresholdValue() != null){
                    boolean isValid = !isWaveExceeded(new BigDecimal(alarmConfig.getThresholdValue()), new BigDecimal(kpiResult.getValue()), new BigDecimal(enmAlarmData.getLastKpiValue()));
                    calcCycleOrClearAlarm(isValid, alarmConfig, kpiResult, enmAlarmData);
                }else {
                    log.error("config id is{},thresholdValue is null,clear dynamic threshold alarm failed!",alarmConfig.getId());
                }

            } else {
                //门限消除
                doThresholdClearAlarm(alarmConfig, kpiResult, enmAlarmData);
            }
        }
    }

    /**
     * 周期消除告警流程
     *
     * @param isValid      是否有效
     * @param alarmConfig  告警配置
     * @param kpiResult    指标结果
     * @param enmAlarmData 当前告警数据
     */
    private void calcCycleOrClearAlarm(boolean isValid, EnipEnmKpiAlarmCondition alarmConfig, EnipKpiResult kpiResult, EnipEnmAlarmData enmAlarmData) {
        //累计时长
        if (isValid) {
            if(kpiResult.getInterval() == null){
                log.error("mq Message (EnipKpiResult) interval is null,summation cleanMinute failed! kpiCreateTime is {}",kpiResult.getKpiCreateTime());
                return;
            }
            enmAlarmData.setCleanMinute(enmAlarmData.getCleanMinute() + kpiResult.getInterval());
            //达到消除周期，消除告警
            if (alarmConfig.getClearThresholdMinute() != null && enmAlarmData.getCleanMinute().compareTo(alarmConfig.getClearThresholdMinute()) >= 0) {
                clearAlarm(alarmConfig, kpiResult, enmAlarmData, enmAlarmData.getCleanMinute());
            } else {
                if(alarmConfig.getClearThresholdMinute() == null){
                    log.error("config id is{},clearThresholdMinute is null,summation cleanMinute failed!",alarmConfig.getId());
                    return;
                }
                enipEnmAlarmDataMapper.updateEnipEnmAlarmData(enmAlarmData);
                saveNoEopsAlarmLog(enmAlarmData.getEnmServer(), alarmConfig.getDoWithType(), enmAlarmData.getCleanMinute(), kpiResult, SEND_FLAG_NOT_SEND, ALARM_STATUS_CREATE, null);
            }
        } else {
            enmAlarmData.setLastKpiValue(kpiResult.getValue());
            //时长清零
            enmAlarmData.setCleanMinute(INIT_MINUTE);
            enipEnmAlarmDataMapper.updateEnipEnmAlarmData(enmAlarmData);
            saveNoEopsAlarmLog(enmAlarmData.getEnmServer(), alarmConfig.getDoWithType(), INIT_MINUTE, kpiResult, SEND_FLAG_NOT_SEND, ALARM_STATUS_CREATE, null);
        }
    }

    /**
     * 门限消除告警流程
     *
     * @param alarmConfig  告警配置
     * @param kpiResult    指标结果
     * @param enmAlarmData 当前告警数据
     */
    private void doThresholdClearAlarm(EnipEnmKpiAlarmCondition alarmConfig, EnipKpiResult kpiResult, EnipEnmAlarmData enmAlarmData) {
        if(alarmConfig.getClearThresholdType() == null || alarmConfig.getClearThresholdValue() == null) {
            log.error("config id is{},clearThresholdType or clearThresholdValue is null,clear threshold alarm failed!",alarmConfig.getId());
            return;
        }
        boolean isExceeded = isClearExceeded(alarmConfig.getClearThresholdType(), new BigDecimal(alarmConfig.getClearThresholdValue()), new BigDecimal(kpiResult.getValue()));
        if (isExceeded) {
            clearAlarm(alarmConfig, kpiResult, enmAlarmData, INIT_MINUTE);
        }
    }


    /**
     * 清除kpi告警
     *
     * @param alarmConfig  告警配置
     * @param kpiResult    告警结果
     * @param enmAlarmData 告警数据
     * @param cleanMinute  清除周期
     */
    private void clearAlarm(EnipEnmKpiAlarmCondition alarmConfig, EnipKpiResult kpiResult, EnipEnmAlarmData enmAlarmData, Integer cleanMinute) {

        Alarm alarm = JSONUtil.toBean(enmAlarmData.getDetailLog(), Alarm.class);
        alarm.getSequence().get(0).getAttribute().setSeverity(Severity.Cleared);
        enmAlarmData.setDetailLog(JSONUtil.parseObj(alarm, false).toString());

        int sendStatus = ENM_POST_STATUS_SUCCESS;
        //非系统内告警
        if (enmAlarmData.getEnmServer() != null && enmAlarmData.getEnmServer() > 0) {
            sendStatus = SendAlarmUtil.sendAlarm(enmAlarmData.getEnmServer() == 1 ? host1 : host2, enmAlarmData.getEnmServer() == 1 ? username1 : username2, enmAlarmData.getEnmServer() == 1 ? password1 : password2, enmAlarmData.getDetailLog());
        }
        if (sendStatus == ENM_POST_STATUS_SUCCESS) {
            enipEnmAlarmDataMapper.deleteEnipEnmAlarmDataById(enmAlarmData.getId());
            saveNoEopsAlarmLog(enmAlarmData.getEnmServer(), alarmConfig.getDoWithType(), cleanMinute, kpiResult, SEND_FLAG_SUCCESS, ALARM_STATUS_CLEAR, enmAlarmData.getDetailLog());
        } else {
            saveNoEopsAlarmLog(enmAlarmData.getEnmServer(), alarmConfig.getDoWithType(), cleanMinute, kpiResult, SEND_FLAG_FAILED, ALARM_STATUS_CLEAR, enmAlarmData.getDetailLog());
        }
    }

    /**
     * 保存非eops的告警日志
     *
     * @param bizType     业务类型
     * @param cleanMinute 清除周期
     * @param kpiResult   指标数据
     * @param sendFlag    发送标志
     * @param alarmStatus 告警状态
     */
    private void saveNoEopsAlarmLog(final Integer enmServer, Integer bizType, Integer cleanMinute, EnipKpiResult kpiResult, Integer sendFlag, Integer alarmStatus, String detailLog) {
        EnipEnmAlarmLog enmAlarmLog = new EnipEnmAlarmLog();
        enmAlarmLog.setBizType(bizType);
        enmAlarmLog.setBizSubType(BIZ_SUB_TYPE_KPI);
        enmAlarmLog.setNetId(kpiResult.getNetId());
        enmAlarmLog.setKpiId(kpiResult.getKpiId());
        enmAlarmLog.setKpiCreateTime(kpiResult.getKpiCreateTime());
        enmAlarmLog.setCreateTime(DateUtil.now());
        enmAlarmLog.setLastKpiValue(kpiResult.getValue());
        enmAlarmLog.setCleanMinute(cleanMinute);
        enmAlarmLog.setAlarmStatus(alarmStatus);
        enmAlarmLog.setSendFlag(sendFlag);
        enmAlarmLog.setEnmServer(enmServer);
        enmAlarmLog.setDetailLog(detailLog);
        enipEnmAlarmLogMapper.insertEnipEnmAlarmLog(enmAlarmLog);
    }

    /**
     * 向enm服务器（发送告警|清除告警）
     *
     * @param netId               网元ID
     * @param config              告警配置
     * @param severity            告警级别
     * @param predefinedThreshold 原值
     * @param currentValue        当前值
     */
    private EnmAlarmObject buildEnmAlarmObject(Long netId, EnipEnmKpiAlarmCondition config, Severity severity, String predefinedThreshold, String currentValue) {
        Attribute attr = new Attribute();
        EnipBaseNetelement netElement = enipBaseNetelementMapper.selectEnipBaseNetelementById(netId);
        attr.setFdn(netElement.getFdn());
        attr.setSpecificProblem(config.getSpecificProblem());
        attr.setProbableCause(config.getProbableCause());
        if (BIZ_TYPE_CHECK == config.getDoWithType()) {
            attr.setProblemText(config.getKpiName() + " item is abnormal according to predefined threshold.");
        } else {
            attr.setProblemText(config.getKpiName() + " Counter is " +
                    getThresholdTypeStr(config.getThresholdType()) + " predefined threshold "
                    + predefinedThreshold + " , current value is " + currentValue);
        }
        attr.setSeverity(severity);
        attr.setAlarmNumber(config.getAlarmNumber());
        EnmAlarmObject alarmResponse = new EnmAlarmObject();
        alarmResponse.setStatusCode(ENM_POST_STATUS_SUCCESS);
        alarmResponse.setAlarmLog(SendAlarmUtil.buildAlarm(attr));
        return alarmResponse;
    }

    /**
     * 根据阈值类型输出告警描述字符串
     *
     * @param thresholdType 门限类型
     * @return 返回告警描述字符串
     */
    private static String getThresholdTypeStr(Integer thresholdType) {
        switch (thresholdType) {
            case 1:
                return "above";
            case 2:
                return "below";
            case 3:
            case 4:
                return "not equal to";
            default:
                return "";
        }
    }

    /**
     * 判断是否超过告警门限
     *
     * @param thresholdType 门限类型
     * @param threshold     门限值
     * @param value         实际值
     * @return 返回判断结果
     */
    private static boolean isExceeded(Integer thresholdType, BigDecimal threshold, BigDecimal value) {
        switch (thresholdType) {
            case 1:
                return value.compareTo(threshold) >= 0;
            case 2:
                return value.compareTo(threshold) <= 0;
            default:
                return false;
        }
    }

    /**
     * 判断是否满足取消告警门限
     *
     * @param thresholdType 门限类型
     * @param threshold     门限值
     * @param value         实际值
     * @return 返回判断结果
     */
    private static boolean isClearExceeded(Integer thresholdType, BigDecimal threshold, BigDecimal value) {
        switch (thresholdType) {
            case 1:
                return value.compareTo(threshold) > 0;
            case 2:
                return value.compareTo(threshold) < 0;
            default:
                return false;
        }
    }

    /**
     * 查询告警配置表，获取当前业务类型当前kpi的配置
     *
     * @param kpiId   公式Id
     * @param bizType 业务类型
     * @return 返回当前配置
     */
    private EnipEnmKpiAlarmCondition getAlarmConfig(Long kpiId, Integer bizType) {

        EnipEnmKpiAlarmCondition configQueryParams = new EnipEnmKpiAlarmCondition();
        configQueryParams.setKpiId(kpiId);
        configQueryParams.setDoWithType(bizType);
        configQueryParams.setStatus(CONFIG_STATUS_ENABLED);
        List<EnipEnmKpiAlarmCondition> configList = enipEnmKpiAlarmConditionMapper.selectEnipEnmKpiAlarmConditionList(configQueryParams);
        if (configList != null && configList.size() > 0) {
            return configList.get(0);
        }
        return null;
    }

}
